﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB;
using System.Collections;
using MongoDB.Configuration;
using System.IO;

using System.Web;
using System.Xml.Serialization;

namespace Helper
{
   public class MongoTools
    {
       private static MongoTools instance = null;
       public static MongoTools Instance
       {get
           {
               if (null == instance)
                   instance = new MongoTools();
               return instance;
           }
       }

       MongoConnectionStringBuilder connectionBuilder = null;

       public MongoTools() {}

       public MongoTools(MongoConnectionStringBuilder connectionBuilder)
       {
           this.connectionBuilder = connectionBuilder;
       }

       protected MongoConnectionStringBuilder ConnectionStringBuilder
       {
           get
           {
               if (null == connectionBuilder)
               {
                   MongoGonfig config = MongoGonfig.ReadConfig();
                   connectionBuilder = config.GetConnectionString();
                   connectionBuilder.Database = config.DataBaseName;
               }
               return connectionBuilder;
           }
       }

       public void ExecuteScript(string Script)
       {
           Mongo mongo = new Mongo(ConnectionStringBuilder.ToString());
           try
           {
               mongo.Connect();
               IMongoDatabase db = mongo.GetDatabase(connectionBuilder.Database);
               db.Eval(Script);
           }
               catch (Exception e)
           {
               SaveErrScript(Script,Guid.NewGuid().ToString () );
               throw e;
            }
           finally {
               mongo.Disconnect();
               mongo.Dispose();
           }
       }

       private  void SaveErrScript(string ErrScript, string FileName)
       {
           string f = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"/MongoErr/";
           Directory.CreateDirectory(f);
           StreamWriter sr = File.CreateText(f + FileName);
           sr.WriteLine(ErrScript);
           sr.Close();
       }
       
       public List<T>  GetCollection <T> (string script)
       {
           Mongo mongo = new Mongo(ConnectionStringBuilder.ToString());
           
           List<T> result = new List<T>();
           IMongoDatabase db = mongo.GetDatabase(ConnectionStringBuilder.Database);
           string currrentID = string.Empty;
           try
           {
               mongo.Connect();
               Document r = db.Eval(script);
            
               //при пустом множестве приходит пустой List<object>
               var rslt = r["retval"];
               if (rslt is List<object>)
                   return result;

               List<Document> lst = (List<Document>)r["retval"];

               foreach (Document d in lst)
               {
                   try
                   {
                       result.Add(Helper.Json<T>.NewtonDeserializeObject (d.ToString()));
                   }
                   catch (Exception e)
                   {
                       SaveErrScript("ErrSerialize:" + d.ToString(), Guid.NewGuid().ToString());
                       continue;
                   }
               }
           }
           finally
           {
               mongo.Disconnect();
           }
           return result;
        }

       public object GetEntity<T>(string script)
       {
           Mongo mongo = new Mongo(ConnectionStringBuilder.ToString());

          IMongoDatabase db = mongo.GetDatabase(ConnectionStringBuilder.Database);
           string currrentID = string.Empty;
           try
           {
               mongo.Connect();
               Document r = db.Eval(script);

               //при пустом множестве приходит пустой List<object>
               var rslt = r["retval"];
               if (null==rslt)
                        return null;

               //List<Document> lst = (List<Document>)r["retval"];
                //foreach (Document d in lst)
               //{
               //    try
               //    {
               //        result.Add(Helper.Json<T>.Deserialize(d.ToString()));
               //    }
               //    catch (Exception e)
               //    {
               //        SaveErrScript("ErrSerialize:" + d.ToString(), Guid.NewGuid().ToString());
               //        continue;
               //    }
               //}
               //return Helper.Json<T>.Deserialize(rslt.ToString());

               return Helper.Json<T>.NewtonDeserializeObject(rslt.ToString());
           }
           finally
           {
               mongo.Disconnect();
           }
           return null;
       }
 
   }
   
    public class MongoGonfig
   {
       public static string FileName { get { return  Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\TI_DATA\mongo.config"; } }

       private static MongoGonfig _mongoGonfig = null;
     
       public static MongoGonfig ReadConfig()
       {
           if (null == _mongoGonfig)
           {
               XmlSerializer serializer = new XmlSerializer(typeof(MongoGonfig));
               using (FileStream fs = new FileStream(FileName, FileMode.Open))
               {
                   _mongoGonfig = (MongoGonfig)serializer.Deserialize(fs);
                   fs.Close();
               }
           }

           return _mongoGonfig;

       }

       public static MongoGonfig DefautCreateConfig()
       {
           MongoGonfig c = new MongoGonfig();
           c.DataBaseName = "TI";
           c.Host = "127.0.0.1";
           c.Port = 27017;
           c.ConnectionTimeout = 60;
           c.WriteConfig();
           return c;
       }

       public void WriteConfig()
       {   
           XmlSerializer mySerializer = new
           XmlSerializer(typeof(MongoGonfig));
           using (StreamWriter myWriter = new StreamWriter(FileName))
           {
               mySerializer.Serialize(myWriter, this);
               myWriter.Close();
           }
       }

       public MongoConnectionStringBuilder GetConnectionString()
       {
           MongoConnectionStringBuilder result = new MongoConnectionStringBuilder();
           result.AddServer(this.Host, this.Port);
           result.Database = DataBaseName;
           result.ConnectionTimeout = new TimeSpan(0, 0, ConnectionTimeout);
           return result;
       }

       #region Properties
       public string Host { get; set; }

       public int Port { get; set; }

       public string DataBaseName { get; set; }

       public int ConnectionTimeout { get; set; }
       #endregion
   }
}
